package RKUjava.awt.event;
import java.awt.event.*;
import java.awt.Component;
import java.util.Vector;
import java.util.Enumeration;

/** The RKUCanvasMouseDispatcher is a kind of event dispatcher for
    javas Canvas class. It can be used to provide a eventlistener service
    for canvas or other Components where partition of the area is useful.
    The main goal of the dispatcher is support the areahandling so you don't 
    need to do it and also to support mouseEntered and mouseExited events on 
    subareas of a canvas.<br>
    Usage: 
    <ol><li>Create a new RKUCanvasMouseDispatcher using the <tt>new</tt>
    keyword.
    <li>Register as many RKUCanvasListeners as you like using the addListener 
    method.
    <li>Add the dispatcher to the Component you want to recieve MouseEvents 
    from by calling addMouseListener on the component. In order to
    receive mouseEntered and mouseExited events you also has to add it as
    a MouseMotionListener. This is because the Java event model will not 
    generate mouseEntered and mouseExited events on subpartions of a Canvas
    because the mousepointer is already inside the Canvas.
    </ol>
    <b>Note:</b> When you register a RKUCanvasMouseDispatcher you can't receive
    other MouseEvents by a normal MouseListener. To get around this add
    a Listener with the method addFallbackListener. This will be invoked if
    no other listener can recieve the event.<br><br>
    <b>Future work:</b> Support for circles, ploygons and other shapes.
*/

public class RKUCanvasMouseDispatcher implements MouseListener, MouseMotionListener
{
  /** The consumestrategy is the way the dispatcher consumes MouseEvents 
      recieved.
      Possible values:<br>
      <table border=0 cellspacing=4>
      <tr><td valign=top>0&nbsp;</td><td valign=top>No consumation - all given events are processed and not consumed. This includes the fallbacklistener.</td></tr>
      <tr><td valign=top>1</td><td valign=top>Consume if some Listener can use the event. It is passed to all listeners and processed by those who can, i.e. overlapping Listeners will both be called. 
If some use the event the fallback listener will not be called.</td></tr>
      <tr><td valign=top>2</td><td valign=top>Consumed by first who can. The 
      listeners are processed in the order they are registered. If noone use the event it is passed
to the fallback listener (if it is registered).</td></tr>
      </table>
  */
  public int theconsumestrategy;

  private Vector mouselisteners;
  private Vector mousemotionlisteners;
  
  private RKUCanvasMouseListener fallbackmouselistener;
  private RKUCanvasMotionListener fallbackmousemotionlistener;

  public RKUCanvasMouseDispatcher(int consumestrategy)
  {
    super();
    theconsumestrategy = consumestrategy;
    mouselisteners = new Vector();
    mousemotionlisteners = new Vector();

    fallbackmouselistener = null;
    fallbackmousemotionlistener = null;
  }

  /** Remove all listeners from the dispatcher. (Including fallback listeneres) */
  public void removeAllListeners()
    {
      mouselisteners.removeAllElements();
      mousemotionlisteners.removeAllElements();
      fallbackmouselistener = null;
      fallbackmousemotionlistener = null;
    }

  /** Remove all area listeners from the dispatcher. (Excluding the fallback listeneres) */
  public void removeAreaListeners()
    {
      mouselisteners.removeAllElements();
      mousemotionlisteners.removeAllElements();
    }

  /** Remove all mouselisteners from the dispatcher. (Including the fallback listener) */
  public void removeAllMouseListeners()
    {
      mouselisteners.removeAllElements();
      fallbackmouselistener = null;
    }

  /** Remove all area mouselisteners from the dispatcher. (Excluding the fallback listener) */
  public void removeAreaMouseListeners()
    {
      mouselisteners.removeAllElements();
    }

  /** Remove all mousemotionlisteners from the dispatcher. (Including the fallback listener) */
  public void removeAllMouseMotionListeners()
    {
      mousemotionlisteners.removeAllElements();
      fallbackmousemotionlistener = null;
    }

  /** Remove all area mousemotionlisteners from the dispatcher. (Excluding the fallback listener) */
  public void removeAreaMouseMotionListeners()
    {
      mouselisteners.removeAllElements();
    }

  /** Add a RKUCanvasMouseListener to this dispatcher. */
  public void addMouseListener(RKUCanvasMouseListener listener)
    {
      mouselisteners.addElement(listener);
    }

  /** Remove a RKUCanvasMouseListener from this dispatcher. */
  public void removeMouseListener(RKUCanvasMouseListener listener)
    {
      mouselisteners.removeElement(listener);
    }

  /** Add a fallbackmouselistener to receive MouseEvents on this dispatcher. */
  public void addFallbackMouseListener(RKUCanvasMouseListener listener)
    {
      fallbackmouselistener = listener;
    }

  /** Remove the fallbackmouselistener on this dispatcher. */
  public void removeFallbackMouseListener(RKUCanvasMouseListener listener)
    {
      fallbackmouselistener = null;
    }

  /** Add a RKUCanvasMotionListener to this dispatcher. */
  public void addMouseMotionListener(RKUCanvasMouseListener listener)
    {
      mousemotionlisteners.addElement(listener);
    }

  /** Remove a RKUCanvasMotionListener from this dispatcher. */
  public void removeMouseMotionListener(RKUCanvasMouseListener listener)
    {
      mousemotionlisteners.removeElement(listener);
    }

  /** Add a fallback mousemotionlistener to receive MouseMotionEvents on  this dispatcher. */
  public void addFallbackMouseMotionListener(RKUCanvasMouseListener listener)
    {
      fallbackmouselistener = listener;
    }

  /** Remove the fallback mousemotionlistener on this dispatcher. */
  public void removeFallbackMouseMotionListener(RKUCanvasMouseListener listener)
    {
      fallbackmouselistener = null;
    }

  private void dispatchMouseEvent(MouseEvent e)
    {
      boolean done, someusedit;
      Enumeration ennum = mouselisteners.elements();

      done = false;
      someusedit = false;
      while (!done && ennum.hasMoreElements()) {
	someusedit = ((RKUCanvasMouseListener)ennum.nextElement()).dispatchMouseEvent(e) || someusedit;

	switch (theconsumestrategy)
	  {
	  case 0:
	    someusedit = false;
	    break;
	  case 2:
	    done = done || someusedit;
	    break;
	  }
      }

      if (!someusedit && fallbackmouselistener!=null) {
	fallbackmouselistener.dispatchMouseEvent(e);
      }
    }

  private void dispatchMouseMotionEvent(MouseEvent e)
    {
      boolean done, someusedit;
      Enumeration ennum = mousemotionlisteners.elements(); 

      done = false;
      someusedit = false;
      while (!done && ennum.hasMoreElements()) {
	someusedit = ((RKUCanvasMotionListener)(ennum.nextElement())).dispatchMouseMotionEvent(e) || someusedit;

	switch (theconsumestrategy)
	  {
	  case 0:
	    someusedit = false;
	    break;
	  case 2:
	    done = done || someusedit;
	    break;
	  }
      }

      if (!someusedit && fallbackmousemotionlistener!=null) {
	fallbackmousemotionlistener.dispatchMouseMotionEvent(e);
      }
    }

  /** <b>Don't override.</b> */
  public void mouseClicked(MouseEvent e)
    {
      dispatchMouseEvent(e);
    }

  /** <b>Don't override.</b> */
  public void mouseEntered(MouseEvent e)
    {
      dispatchMouseEvent(e);
    }

  /** <b>Don't override.</b> */
  public void mouseExited(MouseEvent e)
    {
      dispatchMouseEvent(e);
    }

  /** <b>Don't override.</b> */
  public void mousePressed(MouseEvent e)
    {
      dispatchMouseEvent(e);
    }

  /** <b>Don't override.</b> */
  public void mouseReleased(MouseEvent e)
    {
      dispatchMouseEvent(e);
    }

  /** <b>Don't override.</b> */
  public void mouseMoved(MouseEvent e)
    {
      MouseEvent newevent;

      newevent = new MouseEvent((Component)e.getSource(), e.MOUSE_MOVED, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), 0, e.isPopupTrigger());
      dispatchMouseEvent(newevent);
      dispatchMouseMotionEvent(e);
    }

  /** <b>Don't override.</b> */
  public void mouseDragged(MouseEvent e)
    {
      MouseEvent newevent;

      newevent = new MouseEvent((Component)e.getSource(), e.MOUSE_MOVED, e.getWhen(), e.getModifiers(), e.getX(), e.getY(), 0, e.isPopupTrigger());
      dispatchMouseEvent(newevent);
      dispatchMouseMotionEvent(e);
    }
}
